﻿using System.Collections.Generic;
using System.Linq;
using Rendiciones.Logica.Enumeradores;
using Rendiciones.Logica.Modelos;
using Tesla.Excepciones;
using Tesla.Proveedores;
using Tesla.Validador;

namespace Rendiciones.Logica.Servicios
{
    internal class ServUsuario :IServUsuario
    {
        private readonly IProveedor _proveedor;
        private readonly IValidador _validador;
        private readonly IServRoles _roles;

        public ServUsuario(IProveedor proveedor, IValidador validador, IServRoles roles)
        {
            _proveedor = proveedor;
            _validador = validador;
            _roles = roles;
        }

        public Usuario Leer(string loginOMail)
        {
            try
            {
                var usuario = _proveedor.Read(new Usuario(), new { LoginOMail = loginOMail }, "Recuperar" );
                usuario.Roles = _roles.Buscar(usuario.IdUsuario);
                return usuario;
            }
            catch (NoHuboResultadosException)
            {
                return null;
            }
        }

        public Usuario Leer(int idUsuario)
        {
            try
            {
                var usuario = _proveedor.Read(new Usuario { IdUsuario = idUsuario });
                usuario.Roles = _roles.Buscar(usuario.IdUsuario);
                return usuario;
            }
            catch (NoHuboResultadosException)
            {
                return null;
            }
        }

        public List<Usuario> Buscar(EAreaUsuario area)
        {
            try
            {
                var usuarios = Buscar("");
                return usuarios.Where(u => u.AreaUsuario.Equals(area)).ToList();
            }
            catch (NoHuboResultadosException)
            {
                return new List<Usuario>();
            }
        }

        public List<Usuario> Buscar(string prefix)
        {
            try
            {
                var usuarios = _proveedor.Search(new Usuario(), new { Prefix = prefix }).ToList();
                return usuarios;
            }
            catch(NoHuboResultadosException)
            {
                return new List<Usuario>();
            }
        }

        public void Guardar(ref Usuario usuario)
        {
            Validar(usuario);
            if(usuario.IdUsuario.Equals(0))
                _proveedor.Create(ref usuario);
            else
                _proveedor.Update<Usuario>(usuario);
        }

        public void Desactivar(Usuario usuario)
        {
            _proveedor.Delete<Usuario>(usuario);
        }

        private void Validar(Usuario usuario)
        {
            var mensajesDeValidacion = _validador.Valida(usuario, new Dictionary<string, object>()).ToList();
            if(!string.IsNullOrEmpty(usuario.Username)) {
                var usuarios = Buscar("").Where(u => !u.IdUsuario.Equals(usuario.IdUsuario));
                if(usuarios.Any(u => u.Username.ToLower().Equals(usuario.Username.ToLower())))
                    mensajesDeValidacion.Add(new MensajeDeValidacion { Mensaje = "Ya existe un usuario con el mismo Login", NombreCampo = "Username" });
            }
            if (mensajesDeValidacion.Any(m => !string.IsNullOrEmpty(m.Mensaje)))
                throw new ResultadoValidacionException("Hay campos incompletos o que deben ser modificados", mensajesDeValidacion);
        }

        public Usuario ObtenerUsuarioPorUserPassword(string username, string password)
        {
            try
            {
                var usuario = _proveedor.Read(new Usuario(), new { Login = username, Password = password }, nombreProcedimiento:"sp_Usuario_Login" );
                usuario.Roles = _roles.Buscar(usuario.IdUsuario);
                return usuario;
            }
            catch (NoHuboResultadosException)
            {
                return null;
            }
        }

        public List<Usuario> ActivosCuyoRolEs(ERol rol)
        {
            try
            {
                var usuarios = _proveedor.Search(new Usuario(), new { IdRol = (int)rol }, apellido: "PorRol").ToList();
                return usuarios;
            }
            catch (NoHuboResultadosException)
            {
                return new List<Usuario>();
            }
        }

        public void ActualizaSaldoUsuario(int idUsuario, int saldoNuevo)
        {
            try
            {
                _proveedor.Update<Usuario>(new Usuario(), new {IdUsuario = idUsuario, Saldo = saldoNuevo},
                                  apellido: "ActualizaSaldo");
            }
            catch(ProveedorException) 
            {
                
            }
        }
    }

    public interface IServUsuario
    {
        List<Usuario> Buscar(string prefix);
        List<Usuario> Buscar(EAreaUsuario area);
        Usuario Leer(int idUsuario);
        Usuario Leer(string loginOMail);
        void Guardar(ref Usuario usuario);
        void Desactivar(Usuario usuario);
        Usuario ObtenerUsuarioPorUserPassword(string username, string password);
        List<Usuario> ActivosCuyoRolEs(ERol rol);
        void ActualizaSaldoUsuario(int idUsuario, int saldoNuevo);
    }
}